//1. 空的括号序列是美观的；
//2. 若括号序列 `A` 是美观的，则括号序列 `(A)、[A]、{ A }` 也是美观的；
//3. 若括号序列 `A、B` 都是美观的，则括号序列 `AB` 也是美观的；
//例如[() {}]() 是美观的括号序列，而 )({ )[}](则不是。
//
//现在 Candela想在她绘制的括号序列中，找出其中连续的一段，满足这段子序列是美观的，并且长度尽量大。你能帮帮她吗？
//输入1个长度为 N的括号序列。(5≤N≤10000)
//
//输出
//​一个整数，表示最长的美观的连续子序列的长度。
//样例输入
//
//[[[[]]{}]]
//样例输出
//10

//思路 ： 用栈处理得到每对括号的匹配关系
//2、 根据匹配关系 获得最长的阴影部分

#include <iostream>
#include <algorithm>
#include <stack>
#include <string>
using namespace std;

#define MAX 10000
char str[MAX + 5] ;

int match[MAX + 5] = { 0 };// 存储第 i 的括号位置
stack<int>s;

int main()
{
	cin >> (str + 1); //表示从字符数组的第一位开始存储

	for (int i = 1; str[i]; i++)
	{
		switch (str[i]) {
		case '(':
		case '[':
		case '{': s.push(i); break;

		case ')': {
			if (!s.empty() && str[s.top()] == '(') {
				match[s.top()] = i;
				match[i] = s.top();  //delete
				s.pop();
			}
			else {
				s.push(i); //信息阻隔
			}
		} break;

		case ']': {
			if (!s.empty() && str[s.top()] == '[')
			{
				match[s.top()] = i;
				match[i] = s.top();  //delete
				s.pop();
			}
			else {
				s.push(i); //信息阻隔
			}
		} break;

		case '}': {
			if (!s.empty() && str[s.top()] == '{')
			{
				match[s.top()] = i;
				match[i] = s.top();  //delete
				s.pop();
			}
			else {
				s.push(i); //信息阻隔
			}
		} break;

		}
	}
	//for (int i = 1; str[i]; i++)
	//{
	//	printf("match[%d] = %d\n", i, match[i]);
	//}

	int temp_ans = 0, ans = 0, i = 1;

	while (str[i])
	{
		if (match[i])
		{
			temp_ans += (match[i] - i + 1);
			i = match[i] + 1;
		}
		else
		{
			i += 1;
			temp_ans = 0;
		}
		if (temp_ans > ans) ans = temp_ans;
	}
	cout << ans << endl;

	return 0;
}